use std::{fs, time::Duration};

use actix::*;
use actix_web::{middleware::Logger, web, App, HttpServer};
use tokio::{select, time};

use crate::{
    client, cmd,
    config::{self},
    data, router,
    server::{self, ChatServer},
};

pub async fn start() -> std::io::Result<()> {
    log::info!("Server is listen on :::{}", config::get_server_port());
    log::info!(
        "Server will be running {} workers",
        config::get_server_worker()
    );

    // 获取本机信息
    let server = ChatServer::new().start();
    let cloned_server = server.clone();

    let http_server = HttpServer::new(move || {
        App::new()
            .configure(router::config)
            .app_data(web::Data::new(cloned_server.clone()))
            .wrap(
                Logger::new("%{r}a - - \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\" %t in %Ts")
                    .log_target("data"),
            )
    })
    .disable_signals()
    .workers(config::get_server_worker())
    // .bind(("0.0.0.0", config::get_server_port()))?
    .bind(format!(":::{}", config::get_server_port()))?
    // .bind(("[::]", config::get_server_port()))?
    .run();

    let client_connect_retry_secs = config::get_client_connect_retry_wait();
    let mut cli_handles = Vec::new();
    // 单机模式不需要启动客户端
    if !config::get_server_singleton() {
        let myid = config::get_server_id();

        for server in config::get_members() {
            let server_addr = server.host.unwrap_or(String::from("127.0.0.1"));
            let server_port = server.port.unwrap_or(config::DEFAULT_PORT);
            let server_id = server.id;

            if myid == server_id {
                continue;
            }

            let cli_handle = actix::spawn(async move {
                let mut ch = client::ClientHandler::new(server_addr, server_port, server_id);
                loop {
                    ch.start(
                        &config::get_client_app_key(),
                        &config::get_client_app_secret(),
                    )
                    .await;
                    log::info!("Connection lost contact with {server_id}, wait {client_connect_retry_secs} secs retry again");
                    tokio::time::sleep(Duration::from_secs(client_connect_retry_secs as u64)).await;
                }
            });

            cli_handles.push(cli_handle);
        }

        let hb_handle = tokio::spawn(async move {
            log::debug!("Internal thread initialized");
            let mut intv = time::interval_at(
                tokio::time::Instant::now() + client::START_AFTER,
                client::INTERVAL,
            );

            let pid_file = config::get_server_pid_file();
            let dir = pid_file.parent();
            if let Some(dir) = dir {
                if let Err(e) = fs::write(dir.join(".myid"), format!("{}", config::get_server_id())) {
                    // 为了调试，写不进去也无所谓
                    log::error!("Myid File write failed, path={}, {e}", dir.join(".myid").display())
                }
            }
            loop {
                select! {
                    _ = intv.tick() => {
                        server.do_send(server::Heartbeat);
                        server.do_send(server::Broadcast);
                        // 写pid文件
                        if let Err(e) = fs::write(&pid_file, format!("{}", std::process::id())) {
                            log::error!("PID File write failed, path={}, {e}", pid_file.display())
                        } else {
                            log::debug!("PID File written to {}", pid_file.display())
                        }
                    },
                    else => {
                    }
                }
            }
        });
        cli_handles.push(hb_handle);

        // check事件
        for (srv_name, rse) in config::get_registry_services() {
            let checker_handle = tokio::spawn(async move {
                let mut intv = time::interval_at(
                    tokio::time::Instant::now() + client::START_AFTER,
                    Duration::from_secs(rse.check_interval_secs.unwrap_or(10) as u64),
                );

                loop {
                    select! {
                        _ = intv.tick() => {
                            /*Mutex*/
                            {
                                let &(ref lock, ref _cvar) = &*data::SHARE_GLOBAL_AREA_MUTEX_PAIR.clone();
                                let loc = lock.lock();
                                // Acquired Lock: ReadOnly
                                if !loc.is_leading() {
                                    // 不是leading，不广播
                                    continue;
                                }
                                // Released Lock
                            }

                            if let Some(ref root) = rse.root {
                                log::info!("Checking {}/{}", root, srv_name);
                            } else {
                                log::info!("Checking {}", srv_name);
                            }
                            cmd::run_check_cmd(srv_name.clone(), rse.clone());
                        },
                        else => {
                        }
                    }
                }
            });

            cli_handles.push(checker_handle);
        }
    }

    http_server.await.unwrap();
    for handle in cli_handles {
        handle.await.unwrap();
    }
    // 监控文件变化
    // notify_handle.await.unwrap();

    Ok(())
}

/*
use futures::{channel::mpsc::channel, SinkExt, StreamExt};
use notify::{recommended_watcher, Event, RecursiveMode, Result, Watcher};
use std::path::Path;
// 处理路径监控事件
#[deprecated(note = "")]
fn handle_path_watch(
    res: core::result::Result<Event, notify::Error>,
    server: &actix::Addr<ChatServer>,
    data: Option<Vec<PathBuf>>,
    completed: bool,
) -> (Option<Vec<PathBuf>>, bool) {
    let myid = config::get_server_id();
    /*Mutex*/
    {
        let &(ref lock, ref _cvar) = &*data::SHARE_GLOBAL_AREA_MUTEX_PAIR.clone();
        let loc = lock.lock();
        // Acquired Lock: ReadOnly
        if !loc.is_leading() {
            return (None, true);
        }
        // Released Lock
    }

    let evt = match res {
        Ok(evt) => evt,
        Err(e) => {
            log::error!("[{myid}] - [#] - Path watch event error, cause: {e}");
            return (None, true);
        }
    };

    log::info!("handle_path_watch===> {:?}", evt);

    match evt.kind {
        notify::EventKind::Create(ck) => match ck {
            notify::event::CreateKind::File => {
                let mut fsb = server::FsBroadcast::default();
                fsb.c = Some(evt.paths);
                server.do_send(fsb);
            }
            notify::event::CreateKind::Folder => {
                let mut fsb = server::FsBroadcast::default();
                fsb.cd = Some(evt.paths);
                server.do_send(fsb);
            }
            _ => {}
        },
        notify::EventKind::Remove(rk) => {
            match rk {
                notify::event::RemoveKind::File => {
                    let mut fsb = server::FsBroadcast::default();
                    fsb.r = Some(evt.paths);
                    server.do_send(fsb);
                }
                notify::event::RemoveKind::Folder => {
                    let mut fsb = server::FsBroadcast::default();
                    fsb.rd = Some(evt.paths);
                    server.do_send(fsb);
                }
                _ => log::warn!("rk: {:?}, paths: {:?}", rk, evt.paths),
            }

            // for path in evt.paths {
            //     // 删除
            //     loc.notify_files.insert(Path::new("d::").join(path.clone()), crate::ws::PayloadKind::Remove);
            // }
        }
        notify::EventKind::Modify(mk) => {
            match mk {
                notify::event::ModifyKind::Data(dc) => match dc {
                    notify::event::DataChange::Content | notify::event::DataChange::Any => {
                        let mut fsb = server::FsBroadcast::default();
                        fsb.d = Some(evt.paths);
                        server.do_send(fsb);
                    }
                    _ => log::warn!("mk: {:?}, dc: {:?}, paths: {:?}", mk, dc, evt.paths),
                },
                notify::event::ModifyKind::Metadata(mdk) => {
                    match mdk {
                        notify::event::MetadataKind::AccessTime => {
                            let mut fsb = server::FsBroadcast::default();
                            fsb.a = Some(evt.paths);
                            server.do_send(fsb);
                        }
                        notify::event::MetadataKind::Permissions => {
                            let mut fsb = server::FsBroadcast::default();
                            fsb.p = Some(evt.paths);
                            server.do_send(fsb);
                        }
                        notify::event::MetadataKind::WriteTime => {
                            // let dest = File::options().write(true).open("dest")?;
                            // let times = FileTimes::new()
                            //     .set_accessed(src.accessed()?)
                            //     .set_modified(src.modified()?);
                            // dest.set_times(times)?;
                            let mut fsb = server::FsBroadcast::default();
                            fsb.m = Some(evt.paths);
                            server.do_send(fsb);
                        }
                        // mk: Metadata(Any), mdk: Any, paths: ["/Users/lbk/ayisha/logs/rmp/abc/123"]
                        _ => log::warn!("mk: {:?}, mdk: {:?}, paths: {:?}", mk, mdk, evt.paths),
                    }
                }
                notify::event::ModifyKind::Name(rm) => match rm {
                    notify::event::RenameMode::Any => {
                        if completed {
                            // From
                            return (Some(evt.paths), !completed);
                        }

                        // To
                        if let Some(from_paths) = data {
                            let mut fsb = server::FsBroadcast::default();
                            let mut map = HashMap::new();
                            for (index, from_path) in from_paths.iter().enumerate() {
                                if let Some(to_path) = evt.paths.get(index) {
                                    map.insert(from_path.to_owned(), to_path.to_owned());
                                }
                            }
                            fsb.x = Some(map);
                            server.do_send(fsb);
                        }
                    }
                    notify::event::RenameMode::Both => {
                        log::debug!("Both===> {:?}", evt.paths)
                    }
                    notify::event::RenameMode::From => {
                        log::debug!("Both===> {:?}", evt.paths)
                    }
                    notify::event::RenameMode::To => {
                        log::debug!("Both===> {:?}", evt.paths)
                    }
                    // mv abcd abc
                    // mk: Name(Any), rm: Any, paths: ["/Users/lbk/ayisha/logs/rmp/abcd"]
                    // mk: Name(Any), rm: Any, paths: ["/Users/lbk/ayisha/logs/rmp/abc"]
                    _ => log::warn!("mk: {:?}, rm: {:?}, paths: {:?}", mk, rm, evt.paths),
                },
                _ => {}
            }

            // for path in evt.paths {
            //     if loc.notify_files.get(&path).is_some() {
            //         loc.notify_files
            //             .insert(Path::new("u::").join(path.clone()), crate::ws::PayloadKind::Modify);
            //     }
            // }
        }
        _ => {}
    }

    // 1:
    // a.txt create
    // a.txt modify
    // a.txt remove

    // r:a.txt <namespace>   --->  Boradcast

    // 2:
    // .a.txt.swp create
    // .a.txt.swp remove
    // .a.txt.swp create
    // .a.txt.swp remove
    // Nothing...

    // 3:
    // a.txt modify
    // m:a.txt <namespace>   --->  Boradcast

    (None, true)
}
*/
